package com.ailesson.order.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.ailesson.common.core.AuthContextHolder;
import com.ailesson.common.except.GlobalErrorCodeConstants;
import com.ailesson.common.except.ServiceException;
import com.ailesson.common.reply.PageResult;
import com.ailesson.common.reply.R;
import com.ailesson.common.util.IdGenUtils;
import com.ailesson.order.entity.CouponInfoEntity;
import com.ailesson.order.entity.OrderDetEntity;
import com.ailesson.order.entity.OrderInfoEntity;
import com.ailesson.order.enums.OrderStateEnumm;
import com.ailesson.order.mapper.OrderInfoMapper;
import com.ailesson.order.model.reply.OrderConfirmReply;
import com.ailesson.order.model.reply.OrderInfoPageReply;
import com.ailesson.order.model.reply.OrderInfoReply;
import com.ailesson.order.model.req.OrderFormReq;
import com.ailesson.order.model.req.OrderInfoQueryReq;
import com.ailesson.order.model.req.OrderInfoReq;
import com.ailesson.order.service.CouponInfoService;
import com.ailesson.order.service.OrderDetService;
import com.ailesson.order.service.OrderInfoService;
import com.ailesson.user.dto.UserInfoDto;
import com.ailesson.user.feign.UserFeignClient;
import com.ailesson.video.dto.CourseDto;
import com.ailesson.video.feign.CourseFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfoEntity> implements OrderInfoService {

    @Autowired
    private OrderDetService orderDetService;
    @Autowired
    private CouponInfoService couponInfoService;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private CourseFeignClient courseFeignClient;


    @Override
    public PageResult queryPage(OrderInfoQueryReq params) {
       Page pageTmp = Page.of(params.getPageNo(),params.getPageSize());
       IPage<OrderInfoEntity> page = this.page(
               pageTmp,
               new LambdaQueryWrapper<OrderInfoEntity>()
                       .orderByDesc(OrderInfoEntity::getId)
                       .eq(params.getUserId() != null,OrderInfoEntity::getUserId,params.getUserId())
                       .eq(StringUtils.hasText(params.getOrderStatus()),OrderInfoEntity::getOrderStatus,params.getOrderStatus())
                       .eq(StringUtils.hasText(params.getOutTradeNo()),OrderInfoEntity::getOutTradeNo,params.getOutTradeNo())
                       .ge(params.getCreateTimeBegin() != null,OrderInfoEntity::getCreateTime,params.getCreateTimeBegin())
                       .le(params.getCreateTimeEnd() != null,OrderInfoEntity::getCreateTime,params.getCreateTimeEnd())
                       .likeRight(StringUtils.hasText(params.getPhone()),OrderInfoEntity::getPhone,params.getPhone())
       );
       List<OrderInfoPageReply> replyList = Collections.EMPTY_LIST;
       if (CollectionUtil.isNotEmpty(page.getRecords())){
           replyList = page.getRecords().stream().map(x -> {
               OrderInfoPageReply reply = new OrderInfoPageReply();
               BeanUtils.copyProperties(x, reply);
               fillOrderDetail(reply);
               return reply;
           }).collect(Collectors.toList());
       }
       return new PageResult<>(replyList,page.getTotal());
    }

    private void fillOrderDetail(OrderInfoPageReply reply) {
        List<OrderDetEntity> entityList = orderDetService.list(new LambdaQueryWrapper<OrderDetEntity>()
                .select(OrderDetEntity::getCourseName)
                .eq(OrderDetEntity::getOrderId, reply.getId()));
        List<String> collect = entityList.stream().map(OrderDetEntity::getCourseName).collect(Collectors.toList());
        reply.setCourseNames(StringUtils.collectionToDelimitedString(collect,","));
    }

    @Override
    public OrderInfoReply info(Long id) {
        OrderInfoEntity entity = this.getById(id);
        if (entity != null){
            OrderInfoReply reply = new OrderInfoReply();
            BeanUtils.copyProperties(entity, reply);
            return reply;
        }
        return null;
    }

    @Transactional(
            rollbackFor = {Exception.class}
    )
    @Override
    public void update(OrderInfoReq orderInfo) {
        if (orderInfo.getId() == null || orderInfo.getId() <= 0){
            throw new ServiceException(GlobalErrorCodeConstants.ID_EMPTY_ERROR);
        }
        OrderInfoEntity entity = this.getById(orderInfo.getId());
        if (entity == null){
            throw new ServiceException(GlobalErrorCodeConstants.NOT_EXISTS_ERROR);
        }
        BeanUtils.copyProperties(orderInfo, entity);
        this.updateById(entity);
    }

    @Transactional(
            rollbackFor = {Exception.class}
    )
    @Override
    public Long add(OrderInfoReq orderInfo) {
        orderInfo.setId(null);
        OrderInfoEntity entity = new OrderInfoEntity();
        BeanUtils.copyProperties(orderInfo, entity);
        this.save(entity);
        return entity.getId();
    }

    @Transactional(
            rollbackFor = {Exception.class}
    )
    @Override
    public Long submitOrder(OrderFormReq orderFormVo) {
        //1 获取生成订单条件值
        Long courseId = orderFormVo.getCourseId();
        Long couponId = orderFormVo.getCouponId();
        Long userId = AuthContextHolder.getUserId();

        //2 判断当前用户,针对当前课程是否已经生成订单
        //课程id，用户id
        LambdaQueryWrapper<OrderDetEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderDetEntity::getCourseId,courseId);
        wrapper.eq(OrderDetEntity::getUserId,userId);
        OrderDetEntity orderDetailExists = orderDetService.getOne(wrapper);
        if(orderDetailExists != null) {
            return orderDetailExists.getOrderId();//订单已经存在，直接返回订单id
        }

        //3 根据课程id查询课程信息
        R<CourseDto> courseRes = courseFeignClient.getById(courseId);
        if(!courseRes.ifSuccess() || courseRes.getData() == null) {
            throw new ServiceException(GlobalErrorCodeConstants.NOT_EXISTS_ERROR.getCode(),"课程不存在");
        }
        CourseDto course = courseRes.getData();

        //4 根据用户id查询用户信息
        R<UserInfoDto> userInfoRes = userFeignClient.info(userId);
        if(!userInfoRes.ifSuccess() || userInfoRes.getData() == null) {
            throw new ServiceException(GlobalErrorCodeConstants.NOT_EXISTS_ERROR.getCode(),"用户不存在");
        }
        UserInfoDto  userInfo = userInfoRes.getData();

        //5 根据优惠券id查询优惠券信息
        BigDecimal couponReduce = BigDecimal.ZERO;
        if(couponId != null) {
            CouponInfoEntity couponInfo = couponInfoService.getById(couponId);
            couponReduce = couponInfo.getAmount();
        }

        //6 封装订单生成需要数据到对象，完成添加订单
        //6.1 封装数据到OrderInfo对象里面，添加订单基本信息表
        OrderInfoEntity orderInfo = new OrderInfoEntity();
        orderInfo.setUserId(userId);
        orderInfo.setNickName(userInfo.getNickName());
        orderInfo.setPhone(userInfo.getPhone());
        orderInfo.setProvince(userInfo.getProvince());
        orderInfo.setOriginAmount(course.getPrice());
        orderInfo.setCouponReduce(couponReduce);
        orderInfo.setFinalAmount(orderInfo.getOriginAmount().subtract(orderInfo.getCouponReduce()));

        orderInfo.setOutTradeNo(IdGenUtils.snowflakeStrId(""));
        orderInfo.setTradeBody(course.getTitle());
        orderInfo.setOrderStatus(OrderStateEnumm.CREATED.name());
        baseMapper.insert(orderInfo);

        //6.2 封装数据到OrderDetail对象里面，添加订单详情信息表
        OrderDetEntity orderDetail = new OrderDetEntity();
        orderDetail.setOrderId(orderInfo.getId());
        orderDetail.setUserId(userId);
        orderDetail.setCourseId(courseId);
        orderDetail.setCourseName(course.getTitle());
        orderDetail.setCover(course.getCover());
        orderDetail.setOriginAmount(course.getPrice());
        orderDetail.setCouponReduce(new BigDecimal(0));
        orderDetail.setFinalAmount(orderDetail.getOriginAmount().subtract(orderDetail.getCouponReduce()));
        orderDetService.save(orderDetail);

        //7 更新优惠券状态
        if(null != orderFormVo.getCouponUseId()) {
            couponInfoService.updateCouponInfoUseStatus(orderFormVo.getCouponUseId(), orderInfo.getId());
        }

        //8 返回订单id
        return orderInfo.getId();
    }

    @Override
    public OrderConfirmReply getOrderInfoById(Long id) {
        //id查询订单基本信息和详情信息
        OrderInfoEntity orderInfo = baseMapper.selectById(id);
        OrderDetEntity orderDetail = orderDetService.getOne(new LambdaQueryWrapper<OrderDetEntity>()
                .eq(OrderDetEntity::getOrderId,id).last(" limit 1 "));

        //封装OrderInfoVo
        OrderConfirmReply order = new OrderConfirmReply();
        BeanUtils.copyProperties(orderInfo,order);
        order.setCourseId(orderDetail.getCourseId());
        order.setCourseName(orderDetail.getCourseName());
        return order;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateOrderStatus(String outTradeNo) {
        //根据订单号查询订单
        LambdaQueryWrapper<OrderInfoEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfoEntity::getOutTradeNo,outTradeNo);
        OrderInfoEntity orderInfo = this.getOne(wrapper);
        if (orderInfo == null){
            throw new ServiceException(GlobalErrorCodeConstants.NOT_EXISTS_ERROR.getCode(),"订单不存在");
        }

        //调用方法更新
        this.lambdaUpdate().set(OrderInfoEntity::getOrderStatus,OrderStateEnumm.PAYED.name())
                .eq(OrderInfoEntity::getId,orderInfo.getId())
                .update();
    }
}